package data.handle;

import java.util.LinkedList;

public class LineItemHandle {
    private int partKeyNum;
    private int quantitySum;
    private PartHandle partHandle;

    private Node[] lineItemNodes;
    private HeapLinkedList[] heaps;

    private int flag;
    private Object object = new Object();

    public LineItemHandle(int partKeyNum, PartHandle partHandle){
        this.partKeyNum = partKeyNum;
        this.partHandle = partHandle;
        lineItemNodes = new Node[partKeyNum];
        heaps = new HeapLinkedList[25];

        for (int i = 0; i < partKeyNum; i++) {
            lineItemNodes[i] = new Node();
        }

        for (int i = 0; i < 25; i++) {
            heaps[i] = new HeapLinkedList();
        }
    }

    public Node getKey(int partKey){
        int hash = partKey % partKeyNum;
        Node lineItemNode = lineItemNodes[hash];
        if(lineItemNode.getPartKey() == partKey)
            return lineItemNode;
        else return null;
    }

    public void put(int partKey, int quantity, double price){
        synchronized (object){
            this.quantitySum += quantity;
        }
        int hash = partKey % partKeyNum;
        Node lineItemNode = lineItemNodes[hash];
        byte brandIndex = partHandle.getBrandIndex(partKey);
        int index = indexConversion(brandIndex);
        HeapLinkedList heap = heaps[index];
        synchronized (heap){
            synchronized (lineItemNode){
                if(lineItemNode.getPartKey() == 0){
//                    if(partKey == 1490218){
////                        System.out.println("put0 :" + "partkey : 1490218" + " quantity: " + quantity + " price : " + price);
//                    }
                    lineItemNode.setPartKey(partKey);
                    lineItemNode.setQuantity(quantity);
                    lineItemNode.setPriceSum(price);
//                    if(partKey == 1490218){
////                        System.out.println("insert 1 :" + "partkey : 1490218" + " quantity: " + quantity + " price : " + price);
//                    }
                    heap.insertHeap(lineItemNode);
                } else {
                    lineItemNode.setQuantity(lineItemNode.getQuantity() + quantity);
                    lineItemNode.setPriceSum(lineItemNode.getPriceSum() + price);
                    heap.heapify(lineItemNode);
//                    if(partKey == 1490218){
////                        System.out.println("put... :" + "partkey : 1490218" + " quantity: " + quantity + " price : " + price);
//                    }
                }
            }
        }
    }

    public LinkedList<Node> select(byte brandIndex, double quantity){
        int index = indexConversion(brandIndex);
        HeapLinkedList heap = heaps[index];
        return heap.popAll(quantity);
    }

    public int indexConversion(byte brandIndex){
        int a = 0;
        if(brandIndex <= 15 && brandIndex >= 11){
            a = brandIndex - 11;
        }
        if(brandIndex <= 25 && brandIndex >= 21){
            a = brandIndex - 21 + 5;
        }
        if(brandIndex <= 35 && brandIndex >= 31){
            a = brandIndex - 31 + 10;
        }
        if(brandIndex <= 45 && brandIndex >= 41){
            a = brandIndex - 41 + 15;
        }
        if(brandIndex <= 55 && brandIndex >= 51){
            a = brandIndex - 51 + 20;
        }
        return a;
    }

    public int getQuantitySum(){
        return quantitySum;
    }

    public synchronized void increaseFlag(){
        flag++;
    }

    public int getFlag(){
        return flag;
    }

    public PartHandle getPartHandle() {
        return partHandle;
    }

    public void setPartHandle(PartHandle partHandle) {
        this.partHandle = partHandle;
    }

    public class HeapLinkedList{
        private HeapLinkedListNode head;
        private HeapLinkedListNode tail;
        private byte heapIndex;

        public LinkedList<Node> popAll(double quantity){
            HeapLinkedListNode cur = head;
            LinkedList<Node> list = new LinkedList<>();
            for (int i = 0; i <= heapIndex; i++) {
                Node node = cur.value.pop();
                while(node.getQuantity() < quantity){
//                    System.out.println("node pop : "+"PartKey : " + node.getPartKey() + "quantity : " + node.getQuantity() + "price : " + node.getPriceSum());
                    list.add(node);
                    node = cur.value.pop();
                }
                cur = cur.next;
            }
            return list;
        }

        public void insertHeap(Node node){
            if (head == null){
                head = new HeapLinkedListNode();
                tail = head;
            }

            if (tail.value.size < 2500) {
//                if(node.getPartKey() == 1490218){
////                    System.out.println("insert 1 :" + "partkey : 1490218" + " quantity: " + node.getQuantity() + " price : " + node.getPriceSum());
//                }
                node.setHeapIndex(heapIndex);
                tail.value.insertHeapify(node);
            } else {
//                if(node.getPartKey() == 1490218){
////                    System.out.println("insert 1 :" + "partkey : 1490218" + " quantity: " + node.getQuantity() + " price : " + node.getPriceSum());
//                }
                heapIndex++;
                HeapLinkedListNode newNode = new HeapLinkedListNode();
                tail.next = newNode;
                tail = newNode;
                node.setHeapIndex(heapIndex);
                tail.value.insertHeapify(node);
            }
        }

        public void heapify(Node node){
            byte heapIndex = node.getHeapIndex();
            HeapLinkedListNode cur = head;
            for (int i = 0; i < heapIndex; i++) {
                cur = cur.next;
            }
            cur.value.heapify(node.getPositionInHeap());
        }
    }

    static class HeapLinkedListNode{
        private NodeHeap value;
        private HeapLinkedListNode next;

        public HeapLinkedListNode(){
            value = new NodeHeap(2500);//每个堆结构的大小是2500个节点组织起来
            next = null;
        }

    }

    static class NodeHeap{
        private Node[] heapNodes;
        private int size;

        public NodeHeap(int length){
            heapNodes = new Node[length];
        }

        public Node pop(){
            Node node = heapNodes[0];
            swap(0, size - 1);
            size--;
            heapify(0);
            return node;
        }

        private void insertHeapify(Node node){
                heapNodes[size] = node;
                if(node.getPartKey() == 1490218){
//                    System.out.println("insertHeapify :" + "partkey : 1490218" + " quantity: " + node.getQuantity() + " price : " + node.getPriceSum());
                }
                int index = size++;
                while (heapNodes[index].getQuantity() < heapNodes[(index - 1)/2].getQuantity()){
                    swap(index, (index - 1)/2);
                    index = (index - 1)/2;
                }
//                node.setPositionInHeap(index);
        }

        private void heapify(int index){

            int heapSize = size;
            int left = index * 2 + 1;
            int right = index * 2 + 2;
            while(left < heapSize){
                int small = right < heapSize && heapNodes[left].getQuantity() > heapNodes[right].getQuantity()? right : left;
                if(heapNodes[small].getQuantity() < heapNodes[index].getQuantity()){
                    swap(small, index);
                    left = small * 2 + 1;
                    right = left + 1;
                    index = small;
                }else
                    break;
            }
//            heapNodes[index].setPositionInHeap(index);
        }

        private void swap(int index1, int index2){
            Node a = heapNodes[index1];
            heapNodes[index1] = heapNodes[index2];
            heapNodes[index2] = a;
            heapNodes[index1].setPositionInHeap(index1);
            heapNodes[index2].setPositionInHeap(index2);
        }

    }

    static class Node{
        private int quantity;
        private int partKey;
        private double priceSum;

        private byte heapIndex;
        private int positionInHeap;

        public Node(){
        }
        public Node(int partKey){
            this.partKey = partKey;
        }

        public int getQuantity() {
            return quantity;
        }

        public void setQuantity(int quantity) {
            this.quantity = quantity;
        }

        public int getPartKey() {
            return partKey;
        }

        public void setPartKey(int partKey) {
            this.partKey = partKey;
        }

        public double getPriceSum() {
            return priceSum;
        }

        public void setPriceSum(double priceSum) {
            this.priceSum = priceSum;
        }

         public byte getHeapIndex() {
             return heapIndex;
         }

         public void setHeapIndex(byte heapIndex) {
             this.heapIndex = heapIndex;
         }

         public int getPositionInHeap() {
             return positionInHeap;
         }

         public void setPositionInHeap(int positionInHeap) {
             this.positionInHeap = positionInHeap;
         }
     }

}
